/**************************************************************************
 *
 *  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
 *  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
 *  PURPOSE.
 *
 *  Copyright (C) 1992 - 1996 Microsoft Corporation.  All Rights Reserved.
 *
 **************************************************************************/
/****************************************************************************
 *
 *  WRITEAVI.C
 *
 *  Creates the file OUTPUT.AVI, an AVI file consisting of a rotating clock
 *  face.  This program demonstrates using the functions in AVIFILE.DLL
 *  to make writing AVI files simple.
 *
 *  This is a stripped-down example; a real application would have a user
 *  interface and check for errors.
 *
 ***************************************************************************/
#include "stdafx.h"
#include <windowsx.h>
#include <memory.h>
#include <mmsystem.h>
#include <vfw.h>

#include "writeavi.h"

static HANDLE  MakeDib( HBITMAP hbitmap, UINT bits )
{
	HANDLE              hdib ;
	HDC                 hdc ;
	BITMAP              bitmap ;
	UINT                wLineLen ;
	DWORD               dwSize ;
	DWORD               wColSize ;
	LPBITMAPINFOHEADER  lpbi ;
	LPBYTE              lpBits ;
	
	GetObject(hbitmap,sizeof(BITMAP),&bitmap) ;

	//
	// DWORD align the width of the DIB
	// Figure out the size of the colour table
	// Calculate the size of the DIB
	//
	wLineLen = (bitmap.bmWidth*bits+31)/32 * 4;
	wColSize = sizeof(RGBQUAD)*((bits <= 8) ? 1<<bits : 0);
	dwSize = sizeof(BITMAPINFOHEADER) + wColSize +
		(DWORD)(UINT)wLineLen*(DWORD)(UINT)bitmap.bmHeight;

	//
	// Allocate room for a DIB and set the LPBI fields
	//
	hdib = GlobalAlloc(GHND,dwSize);
	if (!hdib)
		return hdib ;

	lpbi = (LPBITMAPINFOHEADER)GlobalLock(hdib) ;

	lpbi->biSize = sizeof(BITMAPINFOHEADER) ;
	lpbi->biWidth = bitmap.bmWidth ;
	lpbi->biHeight = bitmap.bmHeight ;
	lpbi->biPlanes = 1 ;
	lpbi->biBitCount = (WORD) bits ;
	lpbi->biCompression = BI_RGB ;
	lpbi->biSizeImage = dwSize - sizeof(BITMAPINFOHEADER) - wColSize ;
	lpbi->biXPelsPerMeter = 0 ;
	lpbi->biYPelsPerMeter = 0 ;
	lpbi->biClrUsed = (bits <= 8) ? 1<<bits : 0;
	lpbi->biClrImportant = 0 ;

	//
	// Get the bits from the bitmap and stuff them after the LPBI
	//
	lpBits = (LPBYTE)(lpbi+1)+wColSize ;

	hdc = CreateCompatibleDC(NULL) ;

	GetDIBits(hdc,hbitmap,0,bitmap.bmHeight,lpBits,(LPBITMAPINFO)lpbi, DIB_RGB_COLORS);

	// Fix this if GetDIBits messed it up....
	lpbi->biClrUsed = (bits <= 8) ? 1<<bits : 0;

	DeleteDC(hdc) ;
	GlobalUnlock(hdib);

	return hdib ;
}

CAVIFile::CAVIFile(LPCTSTR lpszFileName, int xdim, int ydim)
 :	FName(lpszFileName),
	xDim(xdim), yDim(ydim), bOK(true), nFrames(0),
	nVideoFrameCount(0),nAudioFrameCount(0),pBmpFileData(0),pWaveFileData(0)
{		
	pfile = NULL;
	ps = NULL;
	psCompressed = NULL;
	psText = NULL;
	aopts[0] = &opts;

	
	pVideoStream = NULL;
	pAviFile = NULL;



	WORD wVer = HIWORD(VideoForWindowsVersion());
	if (wVer < 0x010A)
	{
		// oops, we are too old, blow out of here
		AfxMessageBox(_T("the Version is too old"));
		bOK = false;
	}
	else
	{
		AVIFileInit();
	}

	
}

CAVIFile::~CAVIFile()
{
	if (ps)
		AVIStreamClose(ps);

	if (psCompressed)
		AVIStreamClose(psCompressed);

	if (psText)
		AVIStreamClose(psText);

	if (pfile)
		AVIFileClose(pfile);


	//add by hw
	if (pBmpFileData != 0)
	{
		delete pBmpFileData;
		pBmpFileData = 0;
	}

	if (pWaveFileData != 0)
	{
		delete pWaveFileData;
		pWaveFileData = 0;
	}
	
	nAudioDataLeft=0;

	if (pVideoStream != 0)
		AVIStreamClose(pVideoStream);
	if (*pAudioStream != 0)
		AVIStreamClose(*pAudioStream);
	
	if (pAudioStream != 0)
	{
		delete pAudioStream;
		pAudioStream = 0;
	}
	if (AudioStreamInfo != 0)
	{
		delete AudioStreamInfo;
		AudioStreamInfo = 0;
	}

	if (pAviFile != 0)
		AVIFileRelease(pAviFile);

	WORD wVer = HIWORD(VideoForWindowsVersion());
	if (wVer >= 0x010A)
	{
		AVIFileExit();
	}
	
}

bool CAVIFile::AddFrame(CBitmap& bmp)
{
	HRESULT hr;
	char szMessage[BUFSIZE];

	if (!bOK)
		return false;
	LPBITMAPINFOHEADER alpbi = (LPBITMAPINFOHEADER)GlobalLock(MakeDib(bmp, 24));
	if (alpbi == NULL)
		return false;
	if (xDim>=0 && xDim != alpbi->biWidth)
	{
		GlobalFreePtr(alpbi);
		return false;
	}
	if (yDim>=0 && yDim != alpbi->biHeight)
	{
		GlobalFreePtr(alpbi);
		return false;
	}
	xDim = alpbi->biWidth;
	yDim = alpbi->biHeight;
	if (nFrames == 0)
	{
		hr = AVIFileOpen(&pfile,		    // returned file pointer
			       FName,							// file name
				   OF_WRITE | OF_CREATE,		    // mode to open file with
				   NULL);							// use handler determined
													// from file extension....
		if (hr != AVIERR_OK)
		{
			GlobalFreePtr(alpbi);
			bOK = false;
			return false;
		}
		_fmemset(&strhdr, 0, sizeof(strhdr));
		strhdr.fccType                = streamtypeVIDEO;// stream type
		strhdr.fccHandler             = 0;
		strhdr.dwScale                = 1;
		strhdr.dwRate                 = 15;		    // 15 fps
		strhdr.dwSuggestedBufferSize  = alpbi->biSizeImage;
		SetRect(&strhdr.rcFrame, 0, 0,		    // rectangle for stream
			(int) alpbi->biWidth,
			(int) alpbi->biHeight);

		// And create the stream;
		hr = AVIFileCreateStream(pfile,		    // file pointer
						         &ps,		    // returned stream pointer
								 &strhdr);	    // stream header
		if (hr != AVIERR_OK)
		{
			GlobalFreePtr(alpbi);
			bOK = false;
			return false;
		}

		_fmemset(&opts, 0, sizeof(opts));

		if (!AVISaveOptions(NULL, 0, 1, &ps, (LPAVICOMPRESSOPTIONS FAR *) &aopts))
		{
			GlobalFreePtr(alpbi);
			bOK = false;
			return false;
		}

		hr = AVIMakeCompressedStream(&psCompressed, ps, &opts, NULL);
		if (hr != AVIERR_OK)
		{
			GlobalFreePtr(alpbi);
			bOK = false;
			return false;
		}

		hr = AVIStreamSetFormat(psCompressed, 0,
					   alpbi,	    // stream format
				       alpbi->biSize +   // format size
				       alpbi->biClrUsed * sizeof(RGBQUAD));
		if (hr != AVIERR_OK)
		{
			GlobalFreePtr(alpbi);
			bOK = false;
			return false;
		}

		// Fill in the stream header for the text stream....

		// The text stream is in 60ths of a second....
/*
		_fmemset(&strhdr, 0, sizeof(strhdr));
		strhdr.fccType                = streamtypeTEXT;
		strhdr.fccHandler             = mmioFOURCC('D', 'R', 'A', 'W');
		strhdr.dwScale                = 1;
		strhdr.dwRate                 = 60;
		strhdr.dwSuggestedBufferSize  = sizeof(szText);
		SetRect(&strhdr.rcFrame, 0, (int) alpbi->biHeight,
			(int) alpbi->biWidth, (int) alpbi->biHeight + TEXT_HEIGHT);

		// ....and create the stream.
		hr = AVIFileCreateStream(pfile, &psText, &strhdr);
		if (hr != AVIERR_OK)
		{
			GlobalFreePtr(alpbi);
			bOK = false;
			return false;
		}

		dwTextFormat = sizeof(dwTextFormat);
		hr = AVIStreamSetFormat(psText, 0, &dwTextFormat, sizeof(dwTextFormat));
		if (hr != AVIERR_OK)
		{
			GlobalFreePtr(alpbi);
			bOK = false;
			return false;
		}
*/
	}

	// Jetzt eigentliches Schreiben

		hr = AVIStreamWrite(psCompressed,	// stream pointer
			nFrames * 10,				// time of this frame
			1,				// number to write
			(LPBYTE) alpbi +		// pointer to data
				alpbi->biSize +
				alpbi->biClrUsed * sizeof(RGBQUAD),
				alpbi->biSizeImage,	// size of this frame
			AVIIF_KEYFRAME,			 // flags....
			NULL,
			NULL);
		if (hr != AVIERR_OK)
		{
			GlobalFreePtr(alpbi);
			bOK = false;
			return false;
		}

		// Make some text to put in the file ...
		//LoadString(hInstance, IDS_TEXTFORMAT, szMessage, BUFSIZE );
		/*
		strcpy(szMessage, "This is frame #%d");
			
		int iLen = wsprintf(szText, szMessage, (int)(nFrames + 1));

		// ... and write it as well.
		hr = AVIStreamWrite(psText,
				nFrames * 40,
				1,
				szText,
				iLen + 1,
				AVIIF_KEYFRAME,
				NULL,
				NULL);
		if (hr != AVIERR_OK)
		{
			GlobalFreePtr(alpbi);
			bOK = false;
			return false;
		}
		*/
		GlobalFreePtr(alpbi);

		nFrames++;

	return true;
}
 